package com.itheima.autoCode.service.strategy;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.itheima.autoCode.dto.CodeContext;
import com.itheima.autoCode.service.strategy.code.CodeGenerater;
import com.itheima.w_dto.DependencieInfo;
import com.itheima.w_util.FileUtils;
import com.itheima.w_util.FreemarkerUtil;
import lombok.Getter;

import java.io.File;
import java.util.*;

public abstract class AbstrctractCodeStyleStrategy implements CodeStyleStrategy {

    @Getter
    private final List<List<String>> COMMON_JAVA_DIRS = Arrays.asList(
            Arrays.asList("src", "main", "java"),
            Arrays.asList("src", "test", "java")
    );

    @Getter
    private final List<List<String>> COMMON_RESOURCES_DIRS = Arrays.asList(
            Arrays.asList("src", "main", "resources"),
            Arrays.asList("src", "test", "resources")
    );

    protected Map<String, CodeGenerater> codeGeneraters = new HashMap<>();
    protected boolean registerCodeGenerater(String name,CodeGenerater codeGeneraters) {
        this.codeGeneraters.put(name,codeGeneraters);
        return true;
    }

    public CodeGenerater getCodeGeneraters(String item) {
        if (CollUtil.isEmpty(codeGeneraters)){
            initCodeGeneraters();
        }
        CodeGenerater codeGenerater = this.codeGeneraters.get(item);
        Assert.notNull(codeGenerater,"未找到对应的代码生成器");
        return codeGenerater;
    }

    protected abstract void initCodeGeneraters();


    @Override
    public boolean initProject(CodeContext codeContext) {
        //1.创建项目根目录
        String rootWrapItem=StrUtil.join("-", codeContext.getProjectPrefix(),codeContext.getArtifactId());
        String rootPath = StrUtil.join(File.separator, codeContext.getGenerate_path(), rootWrapItem);
        FileUtils.createDirectory(rootPath);

        //创建模块pom文件
        Map<String, Object> rootDataModel = new HashMap<>();
        rootDataModel.put("groupId", codeContext.getGroupId());
        rootDataModel.put("artifactId", StrUtil.join("-", codeContext.getProjectPrefix(),codeContext.getArtifactId()));
        rootDataModel.put("version", codeContext.getVersion());
        rootDataModel.put("name", codeContext.getProjectName());
        rootDataModel.put("description", codeContext.getProjectDesc());
        rootDataModel.put("packaging", "pom");

        Map<String, String> rootParent = new HashMap<>();
        rootParent.put("groupId", codeContext.getParentGroupId());
        rootParent.put("artifactId", codeContext.getParentArtifactId());
        rootParent.put("version", codeContext.getParentVersion());
        rootDataModel.put("parent", rootParent);

        Map<String, String> properties = new HashMap<>();
        rootDataModel.put("properties", properties);
        properties.put("project.build.sourceEncoding","UTF-8");
        properties.put("maven.compiler.source","1.8");
        properties.put("maven.compiler.target","1.8");


        List<String> modules = new ArrayList<>();
        rootDataModel.put("modules", modules);

        String[] moudles=getMoudles();

        Map<String, List<String>>  denpDict=getdenpyOfMoudles();
        //2.创建模块目录结构
        for (String item : moudles) {
            String wrapItem=StrUtil.join("-", codeContext.getProjectPrefix(),item);
            String moudlePath = StrUtil.join(File.separator, rootPath,wrapItem);
            FileUtils.createDirectory(moudlePath);//创建模块目录
            //父项目添加模块
            modules.add(wrapItem);


            Map<String, Object> dataModel = new HashMap<>();
            dataModel.put("groupId", codeContext.getGroupId());
            dataModel.put("artifactId", wrapItem);
            dataModel.put("version",codeContext.getVersion());

            Map<String, String> parent = new HashMap<>();
            parent.put("groupId", codeContext.getGroupId());
            parent.put("artifactId", StrUtil.join("-", codeContext.getProjectPrefix(),codeContext.getArtifactId()));
            parent.put("version", codeContext.getVersion());
            dataModel.put("parent", parent);

            dataModel.put("properties", properties);

            List<Map<String, Object>> dependencies = new ArrayList<>();
            dataModel.put("dependencies", dependencies);
            //被依赖的模块
            List<String> denpedMoudles = denpDict.get(item);
            if (CollUtil.isNotEmpty(denpedMoudles)){
                for (String denpedMoudle : denpedMoudles) {
                    Map<String, Object> tmpDenp=new HashMap<>();
                    tmpDenp.put("groupId", codeContext.getGroupId());
                    tmpDenp.put("artifactId", StrUtil.join("-", codeContext.getProjectPrefix(),denpedMoudle));
                    tmpDenp.put("version",codeContext.getVersion());
                    dependencies.add(tmpDenp);
                }
            }

            //添加root依赖
            List<DependencieInfo> subDenpys = getDenpyOfWeb(codeContext).get(item);
            addMustDenp(dependencies, subDenpys);


            //生成src下代码
            COMMON_JAVA_DIRS.stream().forEach(dir->{
                String resourcesPath = StrUtil.join(File.separator, moudlePath,FileUtils.joinPath(dir));
                FileUtils.createDirectory(resourcesPath);
                String packagePath = StrUtil.join(File.separator, resourcesPath,FileUtils.joinPath(codeContext.getPackages()));
                FileUtils.createDirectory(packagePath);
                if (!CollUtil.contains(dir,"test")) {
                    codeContext.getProcessParams().setCurPackagePath(packagePath);
                    codeContext.getProcessParams().setCurSrcPath(resourcesPath);
                    codeContext.getProcessParams().getSrcPathDict().put(item,resourcesPath);
                    codeContext.getProcessParams().getPackagePathDict().put(item,packagePath);
                }

            });

            //创建资源目录
            COMMON_RESOURCES_DIRS.stream().forEach(dir->{
                String resourcesPath = StrUtil.join(File.separator, moudlePath,FileUtils.joinPath(dir));
                FileUtils.createDirectory(resourcesPath);
                //生成配置文件
                if (!CollUtil.contains(dir,"test")) {
                    codeContext.getProcessParams().setCurResourcesPath(resourcesPath);
                    codeContext.getProcessParams().getResourcesPathDict().put(item,resourcesPath);
                }
            });

            //创建模块pom文件
            String pomPath = StrUtil.join(File.separator, moudlePath,"pom.xml");
            FreemarkerUtil.renderToFile("pom.ftl", dataModel, new File(pomPath));

            //生成业务表的衍生代码
            createSomeCode(codeContext,item);
        }

        //添加root依赖
        List<DependencieInfo> denpys = getDenpyOfWeb(codeContext).get(codeContext.getArtifactId());
        String rootPomPath = StrUtil.join(File.separator, rootPath,"pom.xml");
        List<Map<String, Object>> dependencies = new ArrayList<>();
        rootDataModel.put("dependencies", dependencies);
        addMustDenp(dependencies, denpys);
        FreemarkerUtil.renderToFile("pom.ftl", rootDataModel, new File(rootPomPath));
        return true;
    }

    protected abstract void createSomeCode(CodeContext codeContext, String item);


    private static void addMustDenp(List<Map<String, Object>> dependencies, List<DependencieInfo> denpys) {
        if (CollUtil.isNotEmpty(denpys)){
            for (DependencieInfo denp : denpys) {
                Map<String, Object> tmpDenp=new HashMap<>();
                tmpDenp.put("groupId", denp.getGroupId());
                tmpDenp.put("artifactId", denp.getArtifactId());
                if (StrUtil.isNotEmpty(denp.getVersion())){
                    tmpDenp.put("version",denp.getVersion());
                }
                if (StrUtil.isNotEmpty(denp.getScope())){
                    tmpDenp.put("scope",denp.getScope());
                }
                if (StrUtil.isNotEmpty(denp.getOptional())){
                    tmpDenp.put("optional",denp.getOptional());
                }
                if (StrUtil.isNotEmpty(denp.getDesc())){
                    tmpDenp.put("desc",denp.getDesc());
                }
                if (CollUtil.isNotEmpty(denp.getExclusions())){
                    List<Map<String, Object>> exclusions = new ArrayList<>();
                    for (DependencieInfo.ExclusionDTO exclusion : denp.getExclusions()) {
                        Map<String, Object> tmpData=new HashMap<>();
                        tmpData.put("groupId", exclusion.getGroupId());
                        tmpData.put("artifactId", exclusion.getArtifactId());
                        exclusions.add(tmpData);
                    }
                    tmpDenp.put("exclusions",exclusions);

                }
                dependencies.add(tmpDenp);
            }
        }
    }



    // 各模块依赖关系

    protected abstract Map<String, List<String>> getdenpyOfMoudles();

    protected abstract Map<String, List<DependencieInfo>> getDenpyOfWeb(CodeContext codeContext);


    protected abstract String[] getMoudles();

}
